#include "AT24C02_Config.h"

/* 8字节全局数据缓冲区，用于存储从AT24C02读取的数据 */
u8 Data[8] = {0};
// 注意：多函数共享此缓冲区，需注意数据同步问题
// 警告：防止数组越界访问，实际使用时应确保索引在0-7范围内

/**
 * @brief AT24C02设备初始化
 * 功能：配置I2C总线参数，准备与AT24C02通信
 * 注意：需确保系统时钟已正确配置
 * 警告：必须在所有数据读写操作前调用此函数
 */
void AT24C02_Config(void)
{
    IIC_Init();  // 初始化I2C硬件接口
}

/**
  * @brief  从AT24C02读取当前地址数据（连续读取模式）
  * @param  None
  * @retval u8 
  *         - 成功：读取到的数据（0x00-0xFF）
  *         - 失败：0xFF 并输出错误信息
  * @note   AT24C02当前地址读取特性：
  *         1. 使用内部地址指针自动递增（上次操作地址+1）
  *         2. 内部地址计数器保存着上次访问时最后一个地址加1的值,
  *            只要芯片有电，该地址就一直保存,当读到最后页的最后字节，
  *            地址会回转到0(页首地址)，当写到某页尾的最后一个字节，
  *            地址会回转到该页的首字节
  *         3. 跨页行为：地址0x07→0x08（同一页），0xFF→0x00（跨页回绕）
  *         4. 典型时序：
  *            ┌───┐ ┌─────┐ ┌─────┐ ┌───┐
  *            │S  │ │0xA1 │ │Data │ │P  │
  *            └───┘ └─────┘ └─────┘ └───┘
  *         
  * @warning 
  *         1. 首次使用前需先写入地址（否则指针未定义）
  *         2. 页边界回绕时不产生错误应答
  *         3. 最大时钟频率400kHz（快速模式）
  *         
  * @example 
  *     // 连续读取示例
  *     AT24C02_Write_Data(0x00, 0x55);  // 先设置地址指针
  *     u8 data1 = AT24C02_Current_Read_Data();  // 读0x00
  *     u8 data2 = AT24C02_Current_Read_Data();  // 自动读0x01
  */
u8 AT24C02_Current_Read_Data(void)
{
    u8 data = 0xFF;  // 默认错误返回值

    /* 阶段1：启动传输 */
    IIC_Start();
    
    /* 阶段2：发送器件地址+读命令 */
    IIC_Send_Byte(0xA1);  // 固定地址0xA1（1010001b）
    if(!IIC_Wait_Ack()) {
        #ifdef I2C_DEBUG
        USART1_Printf("[AT24C02] Current Read Failed: No ACK\r\n");
        #endif
        goto error;
    }

    /* 阶段3：读取数据（发送NACK终止） */
    data = IIC_Read_Byte(0);  // 参数0表示NACK

error:
    /* 阶段4：停止传输（无论成功失败都执行） */
    IIC_Stop();
    IIC_Delay();  // 总线恢复延时

    #ifdef I2C_DEBUG
    if(data != 0xFF) {
        USART1_Printf("[AT24C02] Current Read: 0x%02X\r\n", data);
    }
    #endif

    return data;
}

/**
  * @brief  从AT24C02 EEPROM随机地址读取数据
  * @param  reg_addr: 要读取的存储器地址（0x00-0xFF）
  * @retval u8 
  *         - 成功：读取到的数据（0x00-0xFF）
  *         - 失败：0xFF 并输出错误信息
  * @note   AT24C02器件特性：
  *         1. 容量256x8bit（地址范围0x00-0xFF）
  *         2. 器件地址固定部分：
  *            - 0xA0：写模式（10100000b）
  *            - 0xA1：读模式（10100001b）
  *         3. 典型读取时序：
  *            ┌───┐ ┌─────┐ ┌───────┐ ┌───┐ ┌─────┐ ┌─────┐ ┌───┐
  *            │S  │ │0xA0 │ │Addr   │ │Sr │ │0xA1 │ │Data │ │P  │
  *            └───┘ └─────┘ └───────┘ └───┘ └─────┘ └─────┘ └───┘
  *         
  * @warning 
  *         1. 连续读取时需控制速率（t_WC=5ms）
  *         2. 地址超限将导致循环寻址
  *         
  * @example 
  *     // 读取0x12地址的数据
  *     u8 val = AT24C02_Random_Read_Data(0x12);
  *     if(val != 0xFF) {
  *         printf("Read: 0x%02X\r\n", val);
  *     }
  */
u8 AT24C02_Random_Read_Data(u8 reg_addr)
{
    u8 data = 0xFF;  // 默认错误返回值

    /* 阶段1：启动传输并发送写命令（设置地址指针） */
    IIC_Start();
    IIC_Send_Byte(0xA0);  // 器件地址+写
    if(!IIC_Wait_Ack()) {
        #ifdef I2C_DEBUG
        USART1_Printf("[AT24C02] Device Not Responding(Write Mode)\r\n");
        #endif
        goto error;
    }

    /* 阶段2：发送要读取的存储地址 */
    IIC_Send_Byte(reg_addr);
    if(!IIC_Wait_Ack()) {
        #ifdef I2C_DEBUG
        USART1_Printf("[AT24C02] Address 0x%02X Invalid\r\n", reg_addr);
        #endif
        goto error;
    }

    /* 阶段3：重复启动并切换读模式 */
    IIC_Start();
    IIC_Send_Byte(0xA1);  // 器件地址+读
    if(!IIC_Wait_Ack()) {
        #ifdef I2C_DEBUG
        USART1_Printf("[AT24C02] Device Not Responding(Read Mode)\r\n");
        #endif
        goto error;
    }

    /* 阶段4：读取数据（发送NACK终止） */
    data = IIC_Read_Byte(0);

error:
    /* 阶段5：停止传输（无论成功失败都执行） */
    IIC_Stop();
    IIC_Delay();  // 总线恢复延时

    #ifdef I2C_DEBUG
    if(data != 0xFF) {
        USART1_Printf("[AT24C02] Read OK: Addr[0x%02X]=0x%02X\r\n", reg_addr, data);
    }
    #endif

    return data;
}

/**
 * @brief      从AT24C02设备进行顺序读取数据功能函数
 * @param      Data_length 要读取的数据字节长度（需根据AT24C02设备实际支持的读取长度等合理设置）
 * @param      buffer      用于存储读取数据的缓冲区指针
 * @retval     bool        true-读取成功, false-读取失败
 * @note       1. 此函数遵循I2C协议的顺序读取（Sequential Read）时序，参考提供的时序图。
 *             2. 具体时序步骤：
 *                - 调用IIC_Start()发起I2C通信起始信号。
 *                - 发送设备地址0xA1（读模式）。
 *                - 检查设备应答（IIC_Wait_Ack），若无应答则返回false。
 *                - 通过循环依次读取Data_length字节数据，前Data_length - 1字节发送ACK（使能下次继续读取），
 *                  最后一字节发送NACK（告知设备停止数据发送）。
 *                - 最后调用IIC_Stop()发送停止信号，结束通信。
 *             3. 此版本通过传入缓冲区指针，避免了全局数组的潜在问题，提高了代码的可维护性和安全性。
 * 
 * @note	   顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后，应答ACK。
 * 			   只要EEPROM接收到ACK，将自动增加字地址并继续随时钟发送后面的数据。
 * 			   若达到存储器地址末尾，地址自动回转到0，仍可继续顺序读取数据。
 * 			   主器件不应答"0"，而发送停止条件，即可结束顺序读操作。
 * 
 * @warning    1. 确保传入的buffer指针指向有效且足够大小的内存空间（大小至少为Data_length字节）。
 *             2. 未对Data_length进行设备存储容量相关的范围检查（实际应用中需根据AT24C02特性补充）。
 * @example
 *     u8 buffer[10];
 *     bool result = AT24C02_Sequential_Read_Data(5, buffer);
 *     if (result) {
 *         // 处理buffer中的数据
 *     }
 */

bool AT24C02_Sequential_Read_Data(u8 Data_length, u8 *buffer)
{
    if (buffer == NULL || Data_length == 0)  // 检查输入参数有效性
    {
        return false;  // 无效参数直接返回读取失败
    }

    // 发起I2C通信起始信号
    IIC_Start();

    // 发送AT24C02设备地址（读模式，地址为0xA1）
    IIC_Send_Byte(0xA1);

    // 检查设备是否应答
    if (!IIC_Wait_Ack())  // 如果设备无应答
    {
#ifdef I2C_DEBUG
        // 调试模式下打印错误信息
        USART1_Printf("AT24C02 Sequential Read: Device No Ack\r\n");
#endif
        IIC_Stop();  // 发送停止信号，结束异常通信
        return false;  // 返回读取失败
    }

    // 循环读取指定长度的数据
    for (u8 i = 0; i < Data_length; i++)
    {
        u8 ACK_DEFINE = 1;
        if (i == Data_length - 1)  // 判断是否为最后一个字节
        {
            ACK_DEFINE = 0; // 最后一个字节发送NACK
        }
        // 读取一字节数据，并根据ACK_DEFINE发送相应应答信号
        buffer[i] = IIC_Read_Byte(ACK_DEFINE);
    }

    // 发送I2C通信停止信号
    IIC_Stop();
    // 执行延时操作（具体延时需求根据I2C通信规范和硬件特性确定），确保停止信号稳定
    IIC_Delay();

    return true;  // 正常完成读取操作，返回成功
}
